/*
 * Vec3.h
 *
 *  Created on: 21.09.2009
 *      Author: Christoph Caks
 */

#ifndef Vec3_H_
#define Vec3_H_

// includes
#include "System.h"
#include "Math.h"
#include "types/Vec2.h"

// for isnan() function
#include <math.h>

namespace mehari {
namespace common {

template <typename Real>
class Vec3 {
public:
        // constructors
        Vec3();
        Vec3( const Vec2<Real>& v2V, const Real rZ );
        Vec3( const Real x, const Real y, const Real z );
        Vec3( const Vec3<Real>& v );

        ~Vec3();

        // access
        Real x() const;
        Real& x();
        Real y() const;
        Real& y();
        Real z() const;
        Real& z();
        const Real operator [] ( int iIndex ) const;
        Real& operator [] ( int iIndex );

        // arithmetic operations
        Vec3<Real> operator + ( const Vec3<Real>& vRhs ) const;
        Vec3<Real> operator - ( const Vec3<Real>& vRhs ) const;
        Vec3<Real> operator * ( const Real rRhs ) const;
        Vec3<Real> operator / ( const Real rRhs ) const;
        Vec3<Real> operator - () const;
        Real operator * ( const Vec3<Real>& vRhs ) const;

        Vec3<Real> operator += ( const Vec3<Real>& vRhs );
        Vec3<Real> operator -= ( const Vec3<Real>& vRhs );
        Vec3<Real> operator *= ( const Real rRhs );
        Vec3<Real> operator /= ( const Real rRhs );

        // comparison operations
        bool operator == ( const Vec3<Real>& vRhs) const;
        bool operator != ( const Vec3<Real>& vRhs) const;
        bool operator <  ( const Vec3<Real>& vRhs) const;
        bool operator <= ( const Vec3<Real>& vRhs) const;
        bool operator >  ( const Vec3<Real>& vRhs) const;
        bool operator >= ( const Vec3<Real>& vRhs) const;

        bool isNan() { return isnan( data[0] ) || isnan( data[1] ) || isnan( data[2] ); }

        // geometric operatons
        Real length() const;
        Real squaredLength() const;
        Real normalize();
        Real dot( const Vec3<Real>& vRhs ) const;

        // Vec3 specific
        Vec3<Real> cross( const Vec3<Real>& v3V ) const;
        Vec3<Real> unitCross( const Vec3<Real>& v3V ) const;

        static void orthonormalize( Vec3<Real>& v3V );
        static void generateOrthonormalBasis( Vec3<Real>& v3U, Vec3<Real>& v3V, Vec3<Real>& v3W, bool bUnitLengthW );

        // backwards compatibility
        Vec3<Real> operator ^ ( const Vec3<Real>& v3Rhs ) {
                return cross( v3Rhs );
        }
        Real length2() const { return squaredLength(); }
        void set( const Real x, const Real y, const Real z ) { data[0] = x; data[1] = y; data[2] = z; }
private:
        /**
         * holds the data
         * 0
         * 1
         * 2
         */
        Real data[3];

        int compareArrays( const Vec3<Real>& rkV ) const;
};

#include "../../src/types/Vec3.cpp.inl"

typedef Vec3<float> Vec3f;
typedef Vec3<double> Vec3d;
typedef Vec3<int> Vec3i;

} // namespace common
} // namespace mehari



#endif /* Vec3_H_ */
